
#ifndef PH_OBJ_H
#define PH_OBJ_H

#include <stdint.h>

/*
 * @note 依赖项：
    "cbb_mem.h"     内存管理 -- 可选
*/

// 替换为自己的内存管理头文件 -- 不使用内存管理时可注释掉
#include "cbb_mem.h"
#define PH_MALLOC(size) S_MALLOC(size)

// 不适用内存管理 -- 全局创建协议类
#ifndef PH_MALLOC
#define PH_MALLOC(size) NULL
#endif

// 获取设备接口
#define GET_PH(pstPH, type) ((type*)pstPH->pvFeature)

// 设备注册声明
#define PH_REG_DEC(name, type) \
PH_t* name##_register(type* pstSelf, PH_Check_t fCheck, PH_Append_t fAppend);  \

// 设备注册定义
#define PH_REG_DEF(name, type) \
PH_t* name##_register(type* pstSelf, PH_Check_t fCheck, PH_Append_t fAppend){ \
    /* 输入参数检查 */  \
    if(NULL == pstSelf) return NULL; \
    /* 申请上下文结构体 */ \
    type* _pstSelf = PH_MALLOC(sizeof(type)); \
    /* 上下文结构体检查 */ \
    if(NULL == _pstSelf) return NULL; \
    /* 复制结构体到上下文结构体 */ \
    memcpy(_pstSelf, pstSelf, sizeof(type)); \
    /* 注册协议 */ \
    PH_t* pstPH = cbb_ph_register(_pstSelf, fCheck, fAppend); \
    /* 返回协议 */  \
    return pstPH; \
} \

typedef enum PH_RET{
    PH_OK = 0U,     // 成功
    PH_ERR,         // 失败
} PH_RET_t;

// 缓存区结构体
typedef struct PH_Buf{
    uint8_t* pu8Buffer;     // 缓存区指针
    uint32_t u32BufferLen;  // 缓存区长度
    uint32_t u32DataLen;    // 有效数据长度
} PH_Buf_t;

/**
* @brief 校验crc16校验码
* @param pu8Data 待校验数据指针
* @param u32Len 待校验数据长度
* @return uint8_t 校验结果，1表示校验成功，0表示校验失败
*/
typedef uint8_t
(*PH_Check_t)(uint8_t *pu8Data, uint32_t u32Len);
  
/**
* @brief 追加crc16校验码
* @param pu8Data 待校验数据指针
* @param pu32Len 待校验数据长度指针
* @return uint8_t 校验结果，1表示校验成功，0表示校验失败
*/
typedef uint8_t
(*PH_Append_t)(uint8_t *pu8Data, uint32_t *pu32Len);

/**
 * @brief Protocal Handler Object
 */
typedef struct PH{

    PH_Check_t pfnCheck;    // 校验函数指针
    PH_Append_t pfnAppend;  // 追加校验函数指针
    void* pvFeature;        // 协议特征结构体
    struct PH* pstNext;     // 链表指针
} PH_t;

/**
 * @brief 注册协议
 * @param pvFeature 协议特征结构体指针
 * @param pfnCheck 校验函数指针
 * @param pfnAppend 追加校验函数指针
 * @return PH_t* 协议对象指针
 */
PH_t*
cbb_ph_register(void* pvFeature, PH_Check_t pfnCheck, PH_Append_t pfnAppend);

/**
 * @brief 协议缓存区初始化
 * @param pstBuf 缓存区指针
 * @return @see PH_RET_t
 */
PH_RET_t 
cbb_ph_clear_buf(PH_Buf_t* pstBuf);

#endif // PH_OBJ_H
